﻿/* 
 * Memories Version 1.0
 * Developed by Jigar Desai (http://www.jigar.net/) 
 */
using System;
using System.Web;
using Memories.Entities;

namespace Memories
{
    
    
    /// <summary>
    /// MemoriesDB class contains all static methods to get folder and file informaiton.
    /// </summary>
    public class MemoriesDB
    {
        

        /// <summary>
        /// Gets single Folder information for relative path.
        /// </summary>
        /// <param name="settings">Settings for current application</param>
        /// <param name="relativePath">Friendly or relative path of folder</param>
        /// <returns></returns>
        public static Folder GetFolder(Settings settings, string relativePath)
        {
            Folder folder = GetFolder(settings);

            if (relativePath != "")
            {
                string[] names = relativePath.Trim('/').Split('/');

                foreach (string foldername in names)
                {
                    foreach (Folder subfolder in folder.Folders)
                    {
                        if (subfolder.Name == foldername)
                        {
                            folder = subfolder;
                            break;
                        }
                    }
                }
            }

            return folder;
        }

        /// <summary>
        /// Gets single File information for relative path.
        /// </summary>
        /// <param name="settings">Settings for current application</param>
        /// <param name="friendlyPath">Friendly or relative path of file</param>
        /// <returns></returns>
        public static File GetFile(Settings settings, string friendlyPath)
        {
            string filename = "";
            string folderpath = "";

            friendlyPath = friendlyPath.Trim('/');

            if (friendlyPath.LastIndexOf('/') >= 0)
            {
                filename = friendlyPath.Substring(friendlyPath.LastIndexOf('/') + 1);

                folderpath = friendlyPath.Remove(friendlyPath.LastIndexOf('/'));

                Folder folder = GetFolder(settings, folderpath);

                foreach (File file in folder.Files)
                {
                    if (file.Name == filename)
                    {
                        return file;
                    }
                }

            }

            return null;
        }

        /// <summary>
        /// Gets paged list of Files in existing folder.
        /// </summary>
        /// <param name="folder">Folder object</param>
        /// <param name="page">Current page number</param>
        /// <param name="size">Page size</param>
        /// <param name="pageCount">Total number of pages</param>
        /// <returns>Generic List of File</returns>
        public static System.Collections.Generic.List<File> GetPagedFiles(
            Folder folder, int page, int size, ref int pageCount)
        {
            System.Collections.Generic.List<File> result = new System.Collections.Generic.List<File>();

            double count = folder.Files.Count;
            int start = (page - 1) * size;
            int end = start + size;
            if (end >= count) end = (int)count;

            pageCount = (int)Math.Ceiling(count / size);

            if ((end - start) > 0)
            {
                int j = 0;
                for (int i = start; i < end; i++)
                {
                    result.Add(folder.Files[i]);
                    j += 1;
                }
            }
            return result;
        }

        
        
        /// <summary>
        /// Gets all subfolder and files for current album settings and puts 
        /// in cache for quick access in next access.
        /// </summary>
        /// <param name="settings">Settings for current application</param>
        /// <returns>Folder object</returns>
        public static Folder GetFolder(Settings settings)
        {
            if (HttpContext.Current.Cache[settings.AlbumPath] != null)
            {
                return (Folder)HttpContext.Current.Cache[settings.AlbumPath];
            }

            lock (_syncRoot) {
                return GetFromFileSystem(settings);
            }
            
        }

        
        private readonly static object _syncRoot = new object();

        /// <summary>
        /// Gets Folder information for current application
        /// </summary>
        /// <param name="settings">Settings for current application</param>
        /// <returns>Folder object</returns>
        static Folder GetFromFileSystem(Settings settings)
        {

            if (HttpContext.Current.Cache[settings.AlbumPath] == null)
            {
                Folder folder = GetFolderFromPath(settings, settings.AlbumPath);
                AddDataToCache(folder, settings);
            }

            return (Folder)HttpContext.Current.Cache[settings.AlbumPath];
        }

        /// <summary>
        /// Adds folder information into cache and sets dependency.
        /// </summary>
        /// <param name="folder">Folder object</param>
        /// <param name="settings">Settings for current application</param>
        static void AddDataToCache(Folder folder,Settings settings){
            
            System.IO.DirectoryInfo[] groups = (new System.IO.DirectoryInfo(settings.AlbumPath)).GetDirectories();
            string[] dirs = new String[groups.Length+1];
			for(int i=0;i<groups.Length;i++){
				dirs[i] = groups[i].FullName;
			}
            dirs[groups.Length] = settings.AlbumPath;

            HttpContext.Current.Cache.Insert(settings.AlbumPath, folder, 
				new System.Web.Caching.CacheDependency(dirs));

        }

        /// <summary>
        /// Recursively scans all file and folders inside given path 
        /// and creates folder object.
        /// </summary>
        /// <param name="settings">Settings for current application</param>
        /// <param name="path">Path of Folder</param>
        /// <returns>Folder object</returns>
        static Folder GetFolderFromPath(Settings settings,string path)
        {
            System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(path);
            Folder folder = new Folder(dirInfo);
            folder.RelativePath = RelativePath(settings, folder.FullName);
			
			foreach (System.IO.FileInfo fileInfo in dirInfo.GetFiles())
            {
                if (fileInfo.Name.ToLower().EndsWith(settings.DescriptionFile.ToLower()) )
                {
                    using (System.IO.StreamReader sr = new System.IO.StreamReader(fileInfo.FullName))
                    {
                        folder.Comment = sr.ReadToEnd();
                        sr.Close();
                    }
                    
                }
                else if(settings.FileTypes.HasType(fileInfo.Extension))
                {
                    File file = new File(fileInfo);
                    file.RelativePath = RelativePath(settings, file.FullName);
                    file.Parent = folder;

                    foreach (PropertyExtractorPlugin plugin in settings.PropertyExtractorPlugins)
                    {
                        file = plugin.PropertyPlugin.ExtractValues(file, fileInfo, settings);
                    }

                    folder.Files.Add(file);
                }
            }
			//folder.Files.Sort();
            foreach (System.IO.DirectoryInfo dir in dirInfo.GetDirectories())
            {
                // recursion to same function.
                Folder subfolder = GetFolderFromPath(settings, dir.FullName);
                subfolder.RelativePath = RelativePath(settings, subfolder.FullName);
                subfolder.Parent = folder;
                folder.Folders.Add(subfolder);
            }
            return folder;
        }

        /// <summary>
        /// Gets relative path from full path based on existing settings. 
        /// </summary>
        /// <param name="settings">Settings for current application</param>
        /// <param name="path">Full path</param>
        /// <returns>Relative path</returns>
        static String RelativePath(Settings settings,string path)
        {
            return  path.Replace(settings.AlbumPath, "").Replace(System.IO.Path.DirectorySeparatorChar, '/').Trim('/');
        }

    }
}
